package com.gugee.tiktok.data.consumer.blogger.core.service;

import com.gugee.common.thread.ScheduleTemplate;
import com.gugee.tiktok.common.model.ai.blogger.FaceRecognition;
import com.gugee.tiktok.common.model.constant.ConstAi;
import com.gugee.tiktok.common.model.constant.FaceRecognitionCodeEnum;
import com.gugee.tiktok.common.model.dal.blogger.*;
import com.gugee.tiktok.common.model.mysql.Blogger;
import com.gugee.tiktok.common.model.mysql.BloggerLog;
import com.gugee.tiktok.common.model.mysql.BloggerMain;
import com.gugee.tiktok.common.model.spider.blogger.BloggerResponse;
import com.gugee.tiktok.common.model.spider.blogger.User;
import com.gugee.tiktok.data.common.msg.BloggerMessage;
import com.gugee.tiktok.data.consumer.blogger.config.DataConsumerConfig;
import com.gugee.tiktok.data.consumer.blogger.core.ai.BloggerAiClient;
import com.gugee.tiktok.data.consumer.blogger.core.spider.BloggerSpiderClient;
import com.xiguaji.boot.toolkit.ThreadPoolUtils;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ForkJoinPool;

@Slf4j
@Service
public class BloggerService {

    @Autowired
    BloggerMainRepository bloggerMainRepository;

    @Autowired
    BloggerLogRepository bloggerLogRepository;

    @Autowired
    BloggerRepository bloggerRepository;

    /**
     * redis服务
     */
    @Autowired
    RedisTemplate<String,String> redisTemplate;

    /**
     * 配置
     */
    @Autowired
    DataConsumerConfig dataConsumerConfig;

    /**
     * ai接口
     */
    @Autowired
    BloggerAiClient bloggerAiClient;

    /**
     * kafka
     */
    @Autowired
    KafkaTemplate<Long, BloggerMessage> kafkaTemplateBlogger;

    /**
     * 博主爬虫
     */
    @Autowired
    BloggerSpiderClient bloggerSpiderClient;

    /**
     * user to blogger
     */
    @Autowired
    Blogger.BloggerMapper bloggerMapper;

    @Autowired
    ScheduleTemplate scheduleTemplate;

    ForkJoinPool forkJoinPool;

    private String workName = "bloggerAiExt-worker";

    @PostConstruct
    public void init() {
        forkJoinPool = ThreadPoolUtils.forkJoinPool(dataConsumerConfig.getBloggerAiExtPollSize(), workName);
        scheduleTemplate.attach(workName, forkJoinPool);
    }

    public String getBloggerType(long oUid){
        return bloggerMainRepository.findTypeByoUid(oUid);
    }

//    public List<BloggerMain> getBloggerRanting(String bloggerType, int limit){
//        return bloggerMainRepository.getBloggersByBloggerTypeSortDesc(bloggerType,limit);
//    }
//
//    public List<BloggerMain> getBloggers(int id,int count){
//        return bloggerMainRepository.findBloggersByIdAndCount(id,count);
//    }

    public BloggerMain getBloggerByOUid(long oUid){
        val bloggerMainOptional = bloggerMainRepository.findByoUid(oUid);

        if(bloggerMainOptional.isPresent()){
            return bloggerMainOptional.get();
        }
        return null;
    }

    public Optional<BloggerLog> getBloggerLogByLogType(int logType){
        return bloggerLogRepository.findByLogType(logType);
    }

    public void saveBloggerMain(BloggerMain bloggerMain){
        bloggerMainRepository.save(bloggerMain);
    }

    public void saveBloggerLog(BloggerLog bloggerLog){
        bloggerLogRepository.save(bloggerLog);
    }

    /**
     * 处理博主ai分析年龄、性别任务
     * @param bloggerMessages
     */
    public void bloggerAiExtHandle(List<BloggerMessage> bloggerMessages){
        try {
            forkJoinPool.submit(() -> bloggerMessages.parallelStream().forEach(bloggerMessage -> {
                try {
                    String url = bloggerMessage.getBloggerType();
                    //判断头像是否有效
                    if(!checkExpire(url)){
                        //开始爬博主信息
                        url = runSpiderBlogger(bloggerMessage.getId(),bloggerMessage.getUid(),StringUtils.isEmpty(url));
                    }
                    //调用ai接口
                    if(!StringUtils.isEmpty(url)){
                        callAiAndSave(bloggerMessage,url);
                    }
                } catch (Exception ex) {
                    log.error("BloggerAiExt error. uid:{},{}" ,bloggerMessage.getUid(),ex.getMessage());
                    //异常时要去掉bitmap里的相关记录，保证下次能继续轮到
                    redisTemplate.opsForValue().setBit("blogger_ai_analyze",bloggerMessage.getId(),false);
                }
            })).get();
        } catch (Exception ex) {
            log.error("BloggerAiExt thread error.  {}" ,  ex.getMessage());
        }
    }

    /**
     * 调用ai接口且保存数据
     * @param bloggerMessage
     * @param url
     */
    public void callAiAndSave(BloggerMessage bloggerMessage,String url){
        long uid = bloggerMessage.getUid();
        long id = bloggerMessage.getId();
        //调用ai接口
        try{
            FaceRecognition faceRecognition = bloggerAiClient.getFaceRecognitionByPicUrl(uid,url);
            //处理结果枚举(0：成功，1002：图片下载问题，1003：程序异常， 18：qps上限 222202：图片无人脸)
            if(FaceRecognitionCodeEnum.SUCCESS.getCode() == faceRecognition.getError_code()
                    || FaceRecognitionCodeEnum.PIC_NO_FACE.getCode() == faceRecognition.getError_code()){
                //更新数据库 blogger
                bloggerRepository.updateAiGenderAndAiAgeByoUid(faceRecognition.getAge() <= ConstAi.NOT_ANALYZED ? ConstAi.UNKNOWN : faceRecognition.getAge(),
                        faceRecognition.getGender() == ConstAi.FACE_RECOGNITION_MALE ? ConstAi.MALE :
                                (faceRecognition.getGender() == ConstAi.FACE_RECOGNITION_FEMALE ? ConstAi.FEMALE : ConstAi.UNKNOWN),
                        ConstAi.GENDER_SOURCE_FACE,uid);
                //更新数据库 blogger_main
                bloggerMainRepository.updateAiGenderAndAiAgeByoUid(faceRecognition.getAge() <= ConstAi.NOT_ANALYZED ? ConstAi.UNKNOWN : faceRecognition.getAge(),
                        faceRecognition.getGender() == ConstAi.FACE_RECOGNITION_MALE ? ConstAi.MALE :
                                (faceRecognition.getGender() == ConstAi.FACE_RECOGNITION_FEMALE ? ConstAi.FEMALE : ConstAi.UNKNOWN),
                        ConstAi.GENDER_SOURCE_FACE,uid);
            }else {
                log.error("调用ai人脸识别接口获取性别、年龄接口返回结果 error ,uid:{},errorCode:{},errorMsg:{}",
                        uid,faceRecognition.getError_code(),faceRecognition.getError_msg());
                    //todo 后面需要对这些情况做处理
                    //更新数据库 blogger
                    bloggerRepository.updateAiGenderAndAiAgeByoUid(ConstAi.NOT_ANALYZED,
                            FaceRecognitionCodeEnum.QPS_FULL.getCode() == faceRecognition.getError_code()
                                    ? ConstAi.QPS_FULL :
                                    (FaceRecognitionCodeEnum.PIC_DOWNLOAD_ERROR.getCode() == faceRecognition.getError_code()
                                            ? ConstAi.PIC_NO_FACE : ConstAi.IMPL_ERROR),
                            ConstAi.GENDER_SOURCE_FACE,uid);
                    //QPS 的时候重试
                    if(FaceRecognitionCodeEnum.QPS_FULL.getCode() == faceRecognition.getError_code()
                            && bloggerMessage.getRetryTimes() > 0){
                        bloggerMessage.setBloggerType(url);
                        bloggerMessage.setRetryTimes(bloggerMessage.getRetryTimes() - 1);
                        resendMsg(bloggerMessage);
                    }
            }
        }catch (Exception e){
            log.error("调用ai人脸识别接口获取性别、年龄接口过程 error ,uid:{},url:{},msg:{}",uid,url,e.getMessage());
            return;
        }
    }

    /**
     * 消息重发
     * @param bloggerMessage
     */
    private void resendMsg(BloggerMessage bloggerMessage){
        kafkaTemplateBlogger.send(dataConsumerConfig.getBloggerAiExtTopicOnline(),bloggerMessage);
    }


    /**
     * 爬取博主
     * @param uid
     * @return
     */
    private String runSpiderBlogger(long id,long uid,boolean needUpdate){
        String url = "";
        //根据uid,region调用接口获取播主相关的数据
        BloggerResponse response = bloggerSpiderClient.get(uid, "");
        User user=response.getUser();
        if (user != null) {
            Blogger blogger = bloggerMapper.mapper(user);
            url = blogger.getOAvatar300();
            if(needUpdate){
                blogger.setId(id);
                blogger.setCreateBy("BloggerAiAnalyze");
                blogger.setUpdateBy("BloggerAiExtEvent SpiderBlogger");
                bloggerRepository.save(blogger);
            }
        }
        return url;
    }

    /**
     * 判断头像图片是否过期
     * @param url
     * @return
     */
    private boolean checkExpire(String url){
        if(!StringUtils.isEmpty(url) && url.contains("x-expires=")){
            int startIndex = url.indexOf("x-expires=" + 10);
            if(startIndex + 10 < url.length()){
                try{
                    //头像过期时间戳
                    long expiresTime = System.currentTimeMillis() / 1000 + dataConsumerConfig.getBloggerAvatarExpiresTime() * 3600;
                    long urlExp = Long.parseLong(url.substring(startIndex,startIndex + 10));
                    if(urlExp >= expiresTime){
                        return true;
                    }
                }catch (Exception e){
                    log.debug("BloggerAiExtEvent avatar expires error,msg :{}",e.getMessage());
                }
            }
        }
        return false;
    }
}
